package com.java.main.service;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;

import com.java.main.constant.Errors;
import com.java.main.domain.SysEntity.SysEntityAuto;
import com.java.main.exception.HiBabyGlobalException;
import com.java.main.util.SqlAssembleUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;

import com.java.main.controller.input.PageInput;
import com.java.main.domain.KbmContent;
import com.java.main.util.AutoField;
import com.java.main.util.BoundSql;
import com.java.main.util.StringUtils;

public class SysBaseServiceImpl<T, ID extends Serializable> implements SysBaseService<T, ID> {
	private Logger log = LoggerFactory.getLogger(getClass());
	@Autowired
	private EntityManager entityManager;
	@Value("${encrypt_algorithm}")
	private String encryptAlgorithm;

	@Override
	@Transactional
	public void add(SysEntityAuto entity) {
		entity.setId(null);
		entityManager.persist(entity);
		entityManager.flush();
	}

	@Override
	@Transactional
	public void update(SysEntityAuto entity) {

		Set<String> set = new HashSet<String>();
		set.add("id");
		set.add("createTime");
		set.add("modifyTime");
		set.add("createId");
		set.add("modifiyId");
		// set.add("kbmContent");
		SysEntityAuto originalEntity = (SysEntityAuto) entityManager.find(getGenericType(), entity.getId());
		if (originalEntity == null) {
			throw new HiBabyGlobalException(Errors.DELETE_ERROR);
		}
		StringUtils.copyPropertiesIgnoreNull(entity, originalEntity, set);
		entityManager.merge(originalEntity);
		entityManager.flush();
	}

	private Class getGenericType() {
		Type genType = getClass().getGenericSuperclass();
		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		if (params.length < 0) {
			throw new RuntimeException("Index outof bounds");
		}
		if (!(params[0] instanceof Class)) {
			return Object.class;
		}
		return (Class) params[0];
	}

	@Override
	@Transactional
	public void del(Integer id) {
		SysEntityAuto entity = (SysEntityAuto) entityManager.find(getGenericType(), id);
		if (entity != null) {
			KbmContent kbmContent = new KbmContent();
			kbmContent.setCurrentUserId(-1);
			entity.setKbmContent(kbmContent);
			entity.setSoftDelete(1);
			entityManager.merge(entity);
			entityManager.flush();
		}
	}

	@Override
	@Transactional
	public void del(SysEntityAuto entity) {
		if (entity != null) {
			if (entity.getKbmContent() == null) {
				KbmContent kbmContent = new KbmContent();
				kbmContent.setCurrentUserId(-1);
				entity.setKbmContent(kbmContent);
			}
			entity.setSoftDelete(1);
			entityManager.merge(entity);
			entityManager.flush();
		}
	}

	String getTableName() {
		String tableName = getGenericType().getName();
		tableName = tableName.substring(tableName.lastIndexOf(".") + 1, tableName.length() - 2);
		return StringUtils.getUnderlineName(tableName);
	}

	@Override
	public List<T> findByPage(PageInput input) {
		// String columns = SqlAssembleUtils.buildColumnSql(getGenericType());
		String columns = "*";
		List<AutoField> entityAutoField = SqlAssembleUtils.getEntityAutoField(input, AutoField.WHERE_FIELD);
		StringBuilder querySql = new StringBuilder("SELECT " + columns + " FROM ");
		querySql.append(getTableName());
		querySql.append(" WHERE ");
		querySql.append("soft_delete=0 ");
		if (entityAutoField.size() > 0) {
			BoundSql boundSql = SqlAssembleUtils.builderWhereSql(entityAutoField);
			querySql.append(" and ");
			querySql.append(boundSql.getSql());
		}
		if (StringUtils.isNotEmpty(input.getSortField()) && StringUtils.isNotEmpty(input.getSortOrder())) {
			querySql.append(" order by " + input.getSortField() + " " + input.getSortOrder());
		}
		querySql.append(" limit " + (input.getPage() - 1) * input.getSize() + "," + input.getSize());
		String sql = querySql.toString();
		log.info("执行分页查询sql:" + sql);
		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

	@Override
	public Integer countByPage(PageInput input) {
		List<AutoField> entityAutoField = SqlAssembleUtils.getEntityAutoField(input, AutoField.WHERE_FIELD);
		StringBuilder querySql = getWhereSql(entityAutoField);
		// querySql.append(" limit " + (input.getPage() - 1) + "," +
		// input.getSize());
		String sql = querySql.toString();
		sql = sql.replace("*", "count(*)");
		log.info("执行查询sql:" + sql);
		BigInteger result = null;
		try {
			result = (BigInteger) entityManager.createNativeQuery(sql).getSingleResult();
		} catch (NoResultException e) {
			return 0;
		}
		if (result == null) {
			return 0;
		} else {
			return result.intValue();
		}
	}

	@Override
	public List<T> find(Map<String, Object> param) {
		List<AutoField> entityAutoField = SqlAssembleUtils.mapToAutoFieldList(param);
		StringBuilder querySql = getWhereSql(entityAutoField);
		String sql = querySql.toString();
		log.info("执行查询sql:" + sql);
		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

	@Override
	public List<T> find(Map<String, Object> param, String sortField, String sortOrder) {
		List<AutoField> entityAutoField = SqlAssembleUtils.mapToAutoFieldList(param);
		StringBuilder querySql = getWhereSql(entityAutoField);
		if (StringUtils.isNotEmpty(sortField) && StringUtils.isNotEmpty(sortOrder)) {
			querySql.append(" order by " + sortField + " " + sortOrder);
		}
		String sql = querySql.toString();
		log.info("执行查询sql:" + sql);
		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

	@Override
	public List<T> findOrderBy(Map<String, Object> param, String sortField, String sortOrder) {
		List<AutoField> entityAutoField = SqlAssembleUtils.mapToAutoFieldList(param);
		StringBuilder querySql = getWhereSql(entityAutoField);
		if (StringUtils.isNotEmpty(sortField) && StringUtils.isNotEmpty(sortOrder)) {
			querySql.append(" order by " + sortField + " " + sortOrder);
		}

		String sql = querySql.toString();
		log.info("执行查询sql:" + sql);
		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

	@Override
	public Integer count(Map<String, Object> param) {
		List<AutoField> entityAutoField = SqlAssembleUtils.mapToAutoFieldList(param);
		StringBuilder querySql = getWhereSql(entityAutoField);
		String sql = querySql.toString();
		sql = sql.replace("*", "count(*)");
		log.info("执行查询sql:" + sql);
		BigInteger result = (BigInteger) entityManager.createNativeQuery(sql).getSingleResult();
		if (result == null) {
			return 0;
		} else {
			return result.intValue();
		}
	}

	@Override
	public T findOne(Map<String, Object> param) {
		List<AutoField> entityAutoField = SqlAssembleUtils.mapToAutoFieldList(param);
		StringBuilder querySql = getWhereSql(entityAutoField);
		querySql.append(" limit 0,1");
		String sql = querySql.toString();
		log.info("执行分页查询sql:" + sql);
		try {
			return (T) entityManager.createNativeQuery(sql, getGenericType()).getSingleResult();
		} catch (NoResultException e) {
			return null;
		}
	}
	@Override
	public T findOneBySql( String sql) {
		if (sql == null) {
			throw new HiBabyGlobalException(Errors.SYSTEM_ERROR);
		}
		if (sql.indexOf("where") > -1) {
			sql = sql.substring(0, sql.indexOf("where") + 5) + " soft_delete=0 and "
					+ sql.substring(sql.indexOf("where") + 5);
		} else {
			sql += " where soft_delete=0 " ;
		}
		sql += " limit 0,1";
		log.info("执行查询sql:" + sql);
		try {
			return (T) entityManager.createNativeQuery(sql, getGenericType()).getSingleResult();
		} catch (NoResultException e) {
			return null;
		}
	}
	@Override
	public T findOneById(Integer id) {
		List<AutoField> entityAutoField = new ArrayList<AutoField>();
		{// 设置id查询值
			AutoField autoField = new AutoField();
			autoField.setName("id");
			autoField.setSqlOperator("and");
			autoField.setFieldOperator("=");
			autoField.setValues(new Object[] { id });
			autoField.setType(AutoField.WHERE_FIELD);
			entityAutoField.add(autoField);
		}
		StringBuilder querySql = getWhereSql(entityAutoField);
		querySql.append(" limit 0,1");
		String sql = querySql.toString();
		log.info("执行分页查询sql:" + sql);
		try {
			return (T) entityManager.createNativeQuery(sql, getGenericType()).getSingleResult();
		} catch (NoResultException e) {
			return null;
		}
	}

	/**
	 * 根据AutoField 的list生成where sql语句
	 * 
	 * @param entityAutoField
	 * @return
	 */
	private StringBuilder getWhereSql(List<AutoField> entityAutoField) {
		String columns = "*";
		StringBuilder querySql = new StringBuilder("SELECT " + columns + " FROM ");
		querySql.append(getTableName());
		querySql.append(" WHERE ");
		querySql.append(" soft_delete=0 ");
		if (entityAutoField.size() > 0) {
			BoundSql boundSql = SqlAssembleUtils.builderWhereSql(entityAutoField);
			if (boundSql.getParams().size() > 0) {
				querySql.append(" and " + boundSql.getSql());
			}
		}
		return querySql;
	}

	@Override
	public List<T> findAll() {
		StringBuilder querySql = getWhereSql(new ArrayList<AutoField>());
		String sql = querySql.toString();
		log.info("执行查询sql:" + sql);
		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

	@Override
	public Integer countAll() {
		StringBuilder querySql = getWhereSql(new ArrayList<AutoField>());
		String sql = querySql.toString();
		sql = sql.replace("*", "count(*)");
		log.info("执行查询sql:" + sql);
		BigInteger result = (BigInteger) entityManager.createNativeQuery(sql).getSingleResult();
		if (result == null) {
			return 0;
		} else {
			return result.intValue();
		}
	}
}
